package org.zoomdev.zoom.common.filtter;


import org.zoomdev.zoom.common.filter.Filter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class PatternFilterFactory1 {
    public static Filter<String> createFilter(String pattern) {
        if (pattern == null || pattern.isEmpty() || isAllWildcard(pattern)) {
            return new AlwaysAcceptFilter();
        }
        return new PatternParser(pattern).parse();
    }

    private static boolean isAllWildcard(String pattern) {
        return pattern.chars().allMatch(c -> c == '*');
    }

    // Token类型定义
    private enum TokenType {PATTERN, NOT, AND, OR, LPAREN, RPAREN}

    // 异常类
    public static class PatternException extends RuntimeException {
        public PatternException(String message) {
            super(message);
        }
    }

    // 词法分析器
    private static class Lexer {
        private final String input;
        private int pos;

        Lexer(String input) {
            this.input = input;
            this.pos = 0;
        }

        List<Token> tokenize() {
            List<Token> tokens = new ArrayList<>();
            while (pos < input.length()) {
                char c = input.charAt(pos);
                switch (c) {
                    case '!':
                        tokens.add(new Token(TokenType.NOT, "!"));
                        pos++;
                        break;
                    case '&':
                        tokens.add(new Token(TokenType.AND, "&"));
                        pos++;
                        break;
                    case '|':
                        tokens.add(new Token(TokenType.OR, "|"));
                        pos++;
                        break;
                    case '(':
                        tokens.add(new Token(TokenType.LPAREN, "("));
                        pos++;
                        break;
                    case ')':
                        tokens.add(new Token(TokenType.RPAREN, ")"));
                        pos++;
                        break;
                    default:
                        StringBuilder sb = new StringBuilder();
                        while (pos < input.length() && isPatternChar(input.charAt(pos))) {
                            sb.append(input.charAt(pos));
                            pos++;
                        }
                        if (sb.length() > 0) {
                            tokens.add(new Token(TokenType.PATTERN, normalizePattern(sb.toString())));
                        }
                        break;
                }
            }
            return tokens;
        }

        private boolean isPatternChar(char c) {
            return "!&|()".indexOf(c) < 0;
        }

        private String normalizePattern(String pattern) {
            // 合并连续的*
            String normalized = pattern.replaceAll("\\*+", "*");
            // 处理全*的情况
            return normalized.chars().allMatch(c -> c == '*') ? "*" : normalized;
        }
    }

    // 语法分析器
    private static class PatternParser {
        private final List<Token> tokens;
        private int pos;

        PatternParser(String pattern) {
            this.tokens = new Lexer(pattern).tokenize();
            this.pos = 0;
        }

        Filter<String> parse() {
            if (tokens.isEmpty()) return new AlwaysAcceptFilter();
            return parseExpression();
        }

        private Filter<String> parseExpression() {
            return parseOr();
        }

        private Filter<String> parseOr() {
            Filter<String> left = parseAnd();
            while (match(TokenType.OR)) {
                Filter<String> right = parseAnd();
                left = new OrFilter(left, right);
            }
            return left;
        }

        private Filter<String> parseAnd() {
            Filter<String> left = parseNot();
            while (match(TokenType.AND)) {
                Filter<String> right = parseNot();
                left = new AndFilter(left, right);
            }
            return left;
        }

        private Filter<String> parseNot() {
            if (match(TokenType.NOT)) {
                return new NotFilter(parsePrimary());
            }
            return parsePrimary();
        }

        private Filter<String> parsePrimary() {
            if (match(TokenType.LPAREN)) {
                Filter<String> expr = parseExpression();
                if (!match(TokenType.RPAREN)) {
                    throw new PatternException("Missing closing parenthesis");
                }
                return expr;
            }
            if (current().type == TokenType.PATTERN) {
                return createPatternFilter(consume().value);
            }
            throw new PatternException("Unexpected token: " + current());
        }

        private Token current() {
            if (pos >= tokens.size()) throw new PatternException("Unexpected end of input");
            return tokens.get(pos);
        }

        private boolean match(TokenType type) {
            if (pos < tokens.size() && tokens.get(pos).type == type) {
                pos++;
                return true;
            }
            return false;
        }

        private Token consume() {
            return tokens.get(pos++);
        }

        private Filter<String> createPatternFilter(String pattern) {
            if (pattern.equals("*")) return new AlwaysAcceptFilter();

            List<String> parts = Arrays.stream(pattern.split("\\*", -1))
                    .filter(s -> !s.isEmpty())
                    .collect(Collectors.toList());

            if (parts.size() == 1) {
                return new ExactFilter(parts.get(0));
            }

            boolean startsWith = !pattern.startsWith("*");
            boolean endsWith = !pattern.endsWith("*");

            if (startsWith && endsWith) {
                return new AndFilter(
                        new StartsWithFilter(parts.get(0)),
                        new EndsWithFilter(parts.get(parts.size() - 1))
                );
            }
            if (startsWith) {
                return new StartsWithFilter(parts.get(0));
            }
            if (endsWith) {
                return new EndsWithFilter(parts.get(parts.size() - 1));
            }
            return new ContainsFilter(String.join("*", parts));
        }
    }

    private static class Token {
        final TokenType type;
        final String value;

        Token(TokenType type, String value) {
            this.type = type;
            this.value = value;
        }
    }

    // Filter接口及实现类


    static class AlwaysAcceptFilter implements Filter<String> {
        @Override
        public boolean accept(String value) {
            return true;
        }
    }

    static class ExactFilter implements Filter<String> {
        private final String exact;

        ExactFilter(String exact) {
            this.exact = exact;
        }

        @Override
        public boolean accept(String value) {
            return value != null && value.equals(exact);
        }
    }

    static class StartsWithFilter implements Filter<String> {
        private final String prefix;

        StartsWithFilter(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public boolean accept(String value) {
            return value != null && value.startsWith(prefix);
        }
    }

    static class EndsWithFilter implements Filter<String> {
        private final String suffix;

        EndsWithFilter(String suffix) {
            this.suffix = suffix;
        }

        @Override
        public boolean accept(String value) {
            return value != null && value.endsWith(suffix);
        }
    }

    static class ContainsFilter implements Filter<String> {
        private final String contains;

        ContainsFilter(String contains) {
            this.contains = contains;
        }

        @Override
        public boolean accept(String value) {
            return value != null && value.contains(contains);
        }
    }

    static class NotFilter implements Filter<String> {
        private final Filter<String> filter;

        NotFilter(Filter<String> filter) {
            this.filter = filter;
        }

        @Override
        public boolean accept(String value) {
            return !filter.accept(value);
        }
    }

    static class AndFilter implements Filter<String> {
        private final Filter<String> left;
        private final Filter<String> right;

        AndFilter(Filter<String> left, Filter<String> right) {
            this.left = left;
            this.right = right;
        }

        @Override
        public boolean accept(String value) {
            return left.accept(value) && right.accept(value);
        }
    }

    static class OrFilter implements Filter<String> {
        private final Filter<String> left;
        private final Filter<String> right;

        OrFilter(Filter<String> left, Filter<String> right) {
            this.left = left;
            this.right = right;
        }

        @Override
        public boolean accept(String value) {
            return left.accept(value) || right.accept(value);
        }
    }
}